package com.fessc.develop.handler.processor.send;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.fessc.develop.entity.ApplicationPropertiesVo;
import com.fessc.develop.entity.ccbvo.CCBBankCheckJsonVo;
import com.fessc.develop.entity.comvo.*;
import com.fessc.develop.entity.dbvo.*;
import com.fessc.develop.handler.SignHandler;
import com.fessc.develop.model.enums.*;
import com.fessc.develop.service.interfaces.*;
import com.fessc.develop.utils.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.*;

/**
 * 通用处理器，用于推送预付款信息/跨境付汇处理信息给银行或第三方机构（通用版）
 */

@Slf4j
@Service
public class SendProcessor implements ISendProcessor {

    @Resource
    private ITOrgUrlManageService orgUrlManageService;

    @Resource
    private ITOrgConfigService orgConfigService;

    @Resource
    private ITPaymentService paymentService;

    @Resource
    private ISettleTradeService settleTradeService;

    @Resource
    private ISettleTradeListService settleTradeListService;

    @Resource
    private OkHttpUtil okHttpUtil;

    @Resource
    private SignHandler signHandler;

    @Resource
    private ITCheckResultService checkResultService;

    @Resource
    private IEnclosureService enclosureService;

    @Resource
    private ITCheckDetailService checkDetailService;

    @Resource
    private BankCheckResultService bankCheckResultService;

    @Resource
    private ApplicationPropertiesVo applicationPropertiesVo;

    /**
     * 预付款单笔推送
     */
    @Override
    public void prePaymentProcess(List<TPayment> tPaymentList) {
        try {
            //组装报文
            PrePaymentBodyVo bodyVo = paymentService.fakePrePaymentSendBody(tPaymentList);
            log.info("预付款请求报文明文：" + JSON.toJSONString(bodyVo));

            // 如果系统允许多个定时任务同时运行，或者多个线程运行，可能存在同一条待发送银行的记录在不同的定时任务中
            // 因此这里增加判断，如果该记录状态已经发送改变，可能是已发送银行，甚至都可能已经成功，那么该记录不再发送
            // 系统按批次更新交易状态，同一个批次同时更新为已发送银行，因此只需要判断批次其中一条记录的状态是否更改即可
            TPayment dbPayment = paymentService.getById(tPaymentList.get(0).getId());
            log.info("该批次交易数据库当前状态：" + dbPayment.getPaymentBatchNo() + "，paymentStatus：" + dbPayment.getPaymentStatus() + "，paymentType：" + dbPayment.getPaymentType());
            if (BusiUtil.isNotEquals(dbPayment.getPaymentStatus(), "B") || BusiUtil.isNotEquals(dbPayment.getPaymentType(), "B")) {
                log.info("该批次交易数据库状态已经更改，不再发送至银行：" + tPaymentList.get(0).getPaymentBatchNo());
                return;
            }

            //根据机构查询配置表获取URL,通用默认一个机构只有一个URL
            TOrgUrlManage orgUrlManage = orgUrlManageService.getOrgUrlByOrgCodeAndKey(bodyVo.getBankid(), EnumOrgType.BANK.toString(), EnumTaskCode.PRE_PAYMENT_PUSH.toString());
            String url = orgUrlManage.getInterfaceUrl();
            String publicKey = orgUrlManage.getPubCert();
            String requestBody = JSON.toJSONString(getCommonSendVo(bodyVo, bodyVo.getBankid(), bodyVo.getOrgCode(), EnumServiceCode.COM_FS0002.toString(), publicKey));
            Map<String, String> requestHeaders = okHttpUtil.getRequestHeaders(orgUrlManage.getAppKey(), url, bodyVo.getBankid());
            log.info("预付款请求报文密文：" + requestBody);

            //接口推送
            String responseBody = "";  //密文
            JSONObject jsonObject = new JSONObject();  //明文
            try {
                responseBody = okHttpUtil.doPostJson(url, requestBody, requestHeaders);
                jsonObject = JSONObject.parseObject(responseBody);
                log.info("预付款返回报文密文：" + responseBody);
                jsonObject.put(EnumJsonProperty.RES_DATA.toString(), JSONObject.parseObject(signHandler.decrypt(jsonObject.getString(EnumJsonProperty.RES_DATA.toString()))));
                log.info("预付款返回报文明文：" + JSON.toJSONString(jsonObject));
            } catch (Exception e) {
                log.info("预付款请求返回异常：" + e.getMessage());
            }

            //todo:根据返回处理剩余逻辑,调用成功，则更新paymentStatus
            //先按自己定义的返回来做通用处理
            CommonResDataVo commonResDataVo = getCommonResDataVo(jsonObject, EnumTaskCode.PRE_PAYMENT_PUSH.toString());
            if (BusiUtil.isEquals(EnumResultType.COM_TRAN_STATUS_SUCCESS.getStatusCode(), commonResDataVo.getCode())) {
                // 交易成功，将0000更新到payment_status，同时将交易成功更新到payment_log，将银行扣款流水号更新至bank_refids
                log.info("预付款返回请求成功，修改状态为已经发送银行：" + bodyVo.getPaymentBatchNo());
                paymentService.updatePrePaymentStatusByPaymentBatchNo(EnumPaymentStatus.SEND.toString(), "", "", bodyVo.getPaymentBatchNo());
            } else if (BusiUtil.isEquals(EnumResultType.COM_TRAN_STATUS_FAIL.getStatusCode(), commonResDataVo.getCode())) {
                // 交易失败，将失败的状态码更新到payment_status，并将失败原因更新到payment_log
                log.info("预付款返回请求失败，修改状态为失败：" + bodyVo.getPaymentBatchNo());
                paymentService.updatePrePaymentStatusByPaymentBatchNo(commonResDataVo.getCode(), commonResDataVo.getMsg(), "", bodyVo.getPaymentBatchNo());
            } else if (BusiUtil.isEquals(EnumResultType.COM_TRAN_STATUS_PROCESS.getStatusCode(), commonResDataVo.getCode())) {
                // 交易处理中，修改状态payment_status为已发送银行
                log.info("预付款返回交易处理中，修改状态为已发送银行：" + bodyVo.getPaymentBatchNo());
                paymentService.updatePrePaymentStatusByPaymentBatchNo(EnumPaymentStatus.SEND.toString(), "", "", bodyVo.getPaymentBatchNo());
            } else {
                // 返回报文没有明确的交易状态，不更新交易状态，系统再次发起，银行判断且控制重复交易
                log.info("预付款交易未返回明确状态，不更新交易状态：" + bodyVo.getPaymentBatchNo());
            }

            // 批量更新交易状态
            //paymentService.updateBatchById(tPaymentList); //批量更新

        } catch (Exception e) {
            log.info("预付款交易发生异常：" + e.getMessage());
        }
    }

    /**
     * 预付款退款推送
     *
     * @param tPaymentList 预付款退款集合
     */
    @Override
    public void prePaymentRefundProcess(List<TPayment> tPaymentList) {
        try {
            //组装报文
            PrePaymentRefundBodyVo bodyVo = paymentService.fakePrePaymentRefundSendBody(tPaymentList);
            log.info("预付款退款请求报文明文：" + JSON.toJSONString(bodyVo));

            // 如果系统允许多个定时任务同时运行，或者多个线程运行，可能存在同一条待发送银行的记录在不同的定时任务中
            // 因此这里增加判断，如果该记录状态已经发送改变，可能是已发送银行，甚至都可能已经成功，那么该记录不再发送
            // 系统按批次更新交易状态，同一个批次同时更新为已发送银行，因此只需要判断批次其中一条记录的状态是否更改即可
            TPayment dbPayment = paymentService.getById(tPaymentList.get(0).getId());
            log.info("该批次交易数据库当前状态：" + dbPayment.getPaymentBatchNo() + "，refund：" + dbPayment.getRefund() + "，paymentType：" + dbPayment.getPaymentType() + "，verifyStatus：" + dbPayment.getVerifyStatus());
            if (BusiUtil.isNotEquals(dbPayment.getRefund(), "Y") || BusiUtil.isNotEquals(dbPayment.getPaymentType(), "B") || BusiUtil.isNotEquals(dbPayment.getVerifyStatus(), "N")) {
                log.info("该批次交易数据库状态已经更改，不再发送至银行：" + tPaymentList.get(0).getPaymentBatchNo());
                return;
            }

            //根据机构查询配置表获取URL,通用默认一个机构只有一个URL
            TOrgUrlManage orgUrlManage = orgUrlManageService.getOrgUrlByOrgCodeAndKey(bodyVo.getBankid(), EnumOrgType.BANK.toString(), EnumTaskCode.PRE_PAYMENT_REFUND_PUSH.toString());
            String url = orgUrlManage.getInterfaceUrl();
            String publicKey = orgUrlManage.getPubCert();
            String requestBody = JSON.toJSONString(getCommonSendVo(bodyVo, bodyVo.getBankid(), bodyVo.getOrgCode(), EnumServiceCode.COM_FS0003.toString(), publicKey));
            Map<String, String> requestHeaders = okHttpUtil.getRequestHeaders(orgUrlManage.getAppKey(), url, bodyVo.getBankid());
            log.info("预付款退款请求报文密文：" + requestBody);

            //接口推送
            String responseBody = "";  //密文
            JSONObject jsonObject = new JSONObject();  //明文
            try {
                responseBody = okHttpUtil.doPostJson(url, requestBody, requestHeaders);
                jsonObject = JSONObject.parseObject(responseBody);
                log.info("预付款退款返回报文密文：" + responseBody);
                jsonObject.put(EnumJsonProperty.RES_DATA.toString(), JSONObject.parseObject(signHandler.decrypt(jsonObject.getString(EnumJsonProperty.RES_DATA.toString()))));
                log.info("预付款退款返回报文明文：" + JSON.toJSONString(jsonObject));
            } catch (Exception e) {
                log.info("预付款退款请求返回异常：" + e.getMessage());
            }

            //todo:根据返回处理剩余逻辑,调用成功，则更新paymentStatus
            //先按自己定义的返回来做通用处理
            CommonResDataVo commonResDataVo = getCommonResDataVo(jsonObject, EnumTaskCode.PRE_PAYMENT_REFUND_PUSH.toString());
            if (BusiUtil.isEquals(EnumResultType.COM_TRAN_STATUS_SUCCESS.getStatusCode(), commonResDataVo.getCode())) {
                // 交易成功，将0000回写到refund_status同时将“交易成功”回写到refund_log，退款交易流水号回写到 refund_refids 同时将send2 更改成 N
                log.info("预付款退款返回请求成功，修改状态为已经发送银行：" + bodyVo.getRefundBatchNo());
                paymentService.updatePrePaymentRefundByPaymentBatchNo(EnumPaymentStatus.REFUND_SEND.toString(), "", "", "", "", bodyVo.getRefundBatchNo());
            } else if (BusiUtil.isEquals(EnumResultType.COM_TRAN_STATUS_FAIL.getStatusCode(), commonResDataVo.getCode())) {
                // 交易失败，将失败的状态码回写到refund_status并将失败原因回写到refund_log，同时将refundStatus改为已发送银行Y
                log.info("预付款退款返回请求失败，修改状态为失败：" + bodyVo.getRefundBatchNo());
                paymentService.updatePrePaymentRefundByPaymentBatchNo(EnumPaymentStatus.REFUND_SEND.toString(), commonResDataVo.getCode(), "", "", "", bodyVo.getRefundBatchNo());
            } else if (BusiUtil.isEquals(EnumResultType.COM_TRAN_STATUS_PROCESS.getStatusCode(), commonResDataVo.getCode())) {
                // 交易处理中，修改状态refund_status为已发送银行
                log.info("预付款退款返回交易处理中，修改状态为已发送银行：" + bodyVo.getRefundBatchNo());
                paymentService.updatePrePaymentRefundByPaymentBatchNo(EnumPaymentStatus.REFUND_SEND.toString(), "", "", "", "", bodyVo.getRefundBatchNo());
            } else {
                // 返回报文没有明确的交易状态，不更新交易状态，系统再次发起，银行判断且控制重复交易
                log.info("预付款退款交易未返回明确状态，不更新交易状态：" + bodyVo.getRefundBatchNo());
            }

            // 批量更新交易状态
            //paymentService.updateBatchById(tPaymentList); //批量更新

        } catch (Exception e) {
            log.info("预付款退款交易发生异常：" + e.getMessage());
        }
    }

    /**
     * 跨境付汇推送
     */
    @Override
    public void settleTradeProcess(List<SettleTrade> settleTrades) {
        for (SettleTrade settleTrade : settleTrades) {
            try {
                SettleTradeSendBodyVo bodyVo = settleTradeService.fakeSettleTradeSendBody(settleTrade);
                bodyVo.setPayInstNo(settleTrade.getSettleId());
                log.info("跨境付汇请求报文明文：" + JSON.toJSONString(bodyVo));

                // 如果系统允许多个定时任务同时运行，或者多个线程运行，可能存在同一条待发送银行的记录在不同的定时任务中
                // 因此这里增加判断，如果该记录状态已经发送改变，可能是已发送银行，甚至都可能已经成功，那么该记录不再发送
                SettleTrade dbSettleTrade = settleTradeService.getById(settleTrade.getId());
                log.info("该批次交易数据库当前状态：" + dbSettleTrade.getOrderno() + "，reviewStatus：" + dbSettleTrade.getReviewStatus() + "，orderStatus：" + dbSettleTrade.getOrderStatus() + "，paymentType：" + dbSettleTrade.getPaymentType() + "，paymentTypeSend：" + dbSettleTrade.getPaymentTypeSend());
                if (BusiUtil.isNotEquals(dbSettleTrade.getReviewStatus(), "0") || BusiUtil.isNotEquals(dbSettleTrade.getOrderStatus(), "Y") || BusiUtil.isNotEquals(dbSettleTrade.getPaymentType(), "B") || BusiUtil.isNotEquals(dbSettleTrade.getPaymentTypeSend(), "N")) {
                    log.info("该笔交易数据库状态已经更改，不再发送至银行：" + settleTrade.getOrderno());
                    continue;
                }

                //根据机构查询配置表获取URL,通用默认一个机构只有一个URL
                TOrgUrlManage orgUrlManage = orgUrlManageService.getOrgUrlByOrgCodeAndKey(settleTrade.getBankid().toString(), EnumOrgType.BANK.toString(), EnumTaskCode.SETTLE_TRADE_PUSH.toString());
                String url = orgUrlManage.getInterfaceUrl();
                String publicKey = orgUrlManage.getPubCert();
                String requestBody = JSON.toJSONString(getCommonSendVo(bodyVo, settleTrade.getBankid().toString(), settleTrade.getOrgCode(), EnumServiceCode.COM_FS0005.toString(), publicKey));
                Map<String, String> requestHeaders = okHttpUtil.getRequestHeaders(orgUrlManage.getAppKey(), url, settleTrade.getBankid().toString());
                log.info("跨境付汇请求报文密文：" + requestBody);

                //接口推送
                String responseBody = "";  //密文
                JSONObject jsonObject = new JSONObject();  //明文
                try {
                    responseBody = okHttpUtil.doPostJson(url, requestBody, requestHeaders);
                    jsonObject = JSONObject.parseObject(responseBody);
                    log.info("跨境付汇返回报文密文：" + responseBody);
                    jsonObject.put(EnumJsonProperty.RES_DATA.toString(), JSONObject.parseObject(signHandler.decrypt(jsonObject.getString(EnumJsonProperty.RES_DATA.toString()))));
                    log.info("跨境付汇返回报文明文：" + JSON.toJSONString(jsonObject));
                } catch (Exception e) {
                    log.info("跨境付汇请求返回异常：" + e.getMessage());
                }

                //todo:根据返回处理剩余逻辑,调用成功，则更新paymentStatus
                //先按自己定义的返回来做通用处理
                CommonResDataVo commonResDataVo = getCommonResDataVo(jsonObject, EnumTaskCode.SETTLE_TRADE_PUSH.toString());
                if (BusiUtil.isEquals(EnumResultType.COM_SUCCESS.getStatusCode(), commonResDataVo.getCode())) {
                    //异步接口，返回处理成功，将该笔交易状态修改为已发送银行，payment_type_send更改为Y
                    log.info("跨境付汇返回请求成功，修改状态为已发送银行：" + settleTrade.getSettleId());
                    settleTrade.setPaymentTypeSend(EnumPaymentStatus.SETTLE_TRADE_SEND.toString());
                    settleTradeService.updateSettleTradeStatusRefidsLog(settleTrade, EnumPaymentStatus.SEND.toString()); //更新交易发送银行状态
                } else if (BusiUtil.isNotNull(commonResDataVo.getCode()) && BusiUtil.isNotEquals(EnumResultType.COM_SUCCESS.getStatusCode(), commonResDataVo.getCode())) {
                    //异步接口，返回失败，将 review_status更改为3，reject_date为当前时间，reject_performer为银行直连机构号，
                    //remark 更改为银行返回的失败原因，cancel_send更改为N，payment_type_send更改为Y
                    log.info("跨境付汇返回请求失败，修改状态为失败：" + settleTrade.getSettleId());
                    settleTrade.setPaymentTypeSend(EnumPaymentStatus.SETTLE_TRADE_SEND.toString());
                    settleTrade.setReviewStatus(EnumPaymentStatus.SETTLE_REVIEW_FAIL.toString());
                    settleTrade.setRejectDate(DateUtil.getCurrentLocalDateTime());
                    settleTrade.setRejectPerformer(settleTrade.getOrgCode());
                    settleTrade.setRemark("银行驳回交易失败原因：" + BusiUtil.nvl(commonResDataVo.getMsg(), EnumPaymentStatus.PAYMENT_FAIL_LOG.toString()));
                    settleTrade.setCancelSend(EnumPaymentStatus.SETTLE_CANCEL_SEND.toString());
                    settleTradeService.updateSettleTradeStatusRefidsLog(settleTrade, EnumPaymentStatus.PAYMENT_FAIL.toString()); //更新交易失败状态
                    log.info("更新跨境付订单汇明细状态为未跨境付汇：" + settleTrade.getSettleId());
                    settleTradeListService.updateSettleTradeListStatus(settleTrade.getSettleId(), "N");
                } else {
                    //返回报文没有明确的交易状态，不更新交易状态，系统再次发起
                    log.info("跨境付汇已经发送银行，但未返回明确交易状态，不更新交易状态：" + settleTrade.getSettleId());
                }
            } catch (Exception e) {
                log.info("跨境付汇交易发生异常：" + e.getMessage());
            }
        }
    }

    /**
     * 预付款交易状态推送
     *
     * @param tPaymentList 预付款集合
     */
    @Override
    public void prePaymentStatusProcess(List<TPayment> tPaymentList) {
        try {
            //组装报文
            PrePaymentRefundStatusVo bodyVo = paymentService.fakePrePaymentStatusSendBody(tPaymentList, EnumCallBackOption.PRE_PAYMENT_STATUS.toString());
            log.info("预付款交易状态查询请求报文明文：" + JSON.toJSONString(bodyVo));

            //根据机构查询配置表获取URL,通用默认一个机构只有一个URL
            TOrgUrlManage orgUrlManage = orgUrlManageService.getOrgUrlByOrgCodeAndKey(bodyVo.getBankid(), EnumOrgType.BANK.toString(), EnumTaskCode.PRE_PAYMENT_STATUS_PUSH.toString());
            String url = orgUrlManage.getInterfaceUrl();
            String publicKey = orgUrlManage.getPubCert();
            String requestBody = JSON.toJSONString(getCommonSendVo(bodyVo, bodyVo.getBankid(), bodyVo.getOrgCode(), EnumServiceCode.COM_FS0004.toString(), publicKey));
            Map<String, String> requestHeaders = okHttpUtil.getRequestHeaders(orgUrlManage.getAppKey(), url, bodyVo.getBankid());
            log.info("预付款交易状态查询请求报文密文：" + requestBody);

            //接口推送
            String responseBody = "";  //密文
            JSONObject jsonObject = new JSONObject();  //明文
            try {
                responseBody = okHttpUtil.doPostJson(url, requestBody, requestHeaders);
                jsonObject = JSONObject.parseObject(responseBody);
                log.info("预付款交易状态查询返回报文密文：" + responseBody);
                jsonObject.put(EnumJsonProperty.RES_DATA.toString(), JSONObject.parseObject(signHandler.decrypt(jsonObject.getString(EnumJsonProperty.RES_DATA.toString()))));
                log.info("预付款交易状态查询返回报文明文：" + JSON.toJSONString(jsonObject));
            } catch (Exception e) {
                log.info("预付款交易状态查询请求返回异常：" + e.getMessage());
            }

            //todo:根据返回处理剩余逻辑,调用成功，则更新paymentStatus
            //先按自己定义的返回来做通用处理
            CommonResDataVo commonResDataVo = getCommonResDataVo(jsonObject, EnumTaskCode.PRE_PAYMENT_STATUS_PUSH.toString());
            JSONArray tranResult = jsonObject.getJSONObject(EnumJsonProperty.RES_DATA.toString()).getJSONArray(EnumJsonProperty.RES_TRANRESULT.toString());
            List<TPayment> tPaymentUpdateList = new ArrayList<>();
            if (BusiUtil.isEquals(EnumResultType.COM_TRAN_STATUS_SUCCESS.getStatusCode(), commonResDataVo.getCode())) {
                for (Object obj : tranResult) {
                    TPayment paymentUpdate = new TPayment();
                    try {
                        JSONObject object = (JSONObject) obj; // 确保对象是JSONObject类型
                        if (BusiUtil.isEquals(EnumResultType.COM_TRAN_STATUS_SUCCESS.getStatusCode(), object.getString(EnumJsonProperty.RES_STATUS.toString()))) {
                            // 交易成功，将0000更新到payment_status，将交易成功更新到payment_log，同时将银行扣款流水号更新至bank_refids
                            log.info("预付款交易状态查询返回交易成功，修改状态为成功：" + object.getString(EnumJsonProperty.RES_SUBORDERNO.toString()));
                            paymentUpdate.setPaymentBatchNo(bodyVo.getBatchSerialNo());
                            paymentUpdate.setSuborderno(object.getString(EnumJsonProperty.RES_SUBORDERNO.toString()));
                            paymentUpdate.setPaymentStatus(EnumPaymentStatus.PAYMENT_SUCCESS.toString());
                            paymentUpdate.setPaymentLog(EnumPaymentStatus.PAYMENT_SUCCESS_LOG.toString());
                            paymentUpdate.setBankRefids(BusiUtil.nvl(object.getString(EnumJsonProperty.RES_BANKSEQNO.toString()), ""));  //银行交易流水号
                            if (BusiUtil.isNotNull(object.getString(EnumJsonProperty.RES_CORETIME.toString())) && object.getString(EnumJsonProperty.RES_CORETIME.toString()).length() == 14) {
                                paymentUpdate.setPaymentWorkdate(DateUtil.dateToString(DateUtil.stringToDateTime(object.getString(EnumJsonProperty.RES_CORETIME.toString())), DateUtil.DATE_TIME_FORMAT));  //银行扣款时间
                            }
                            tPaymentUpdateList.add(paymentUpdate);
                        } else if (BusiUtil.isEquals(EnumResultType.COM_TRAN_STATUS_FAIL.getStatusCode(), object.getString(EnumJsonProperty.RES_STATUS.toString()))) {
                            // 交易失败，将失败的状态码更新到payment_status，并将失败原因更新到payment_log
                            log.info("预付款交易状态查询返回交易失败，修改状态为失败：" + object.getString(EnumJsonProperty.RES_SUBORDERNO.toString()));
                            paymentUpdate.setPaymentBatchNo(bodyVo.getBatchSerialNo());
                            paymentUpdate.setSuborderno(object.getString(EnumJsonProperty.RES_SUBORDERNO.toString()));
                            paymentUpdate.setPaymentStatus(BusiUtil.nvl(object.getString(EnumJsonProperty.RES_CODE.toString()), EnumPaymentStatus.PAYMENT_FAIL.toString()));
                            paymentUpdate.setPaymentLog(BusiUtil.nvl(object.getString(EnumJsonProperty.RES_MSG.toString()), EnumPaymentStatus.PAYMENT_FAIL_LOG.toString()));
                            tPaymentUpdateList.add(paymentUpdate);
                        } else {
                            // 报文未返回最终交易状态（成功、失败），不更新交易状态
                            log.info("预付款交易状态查询未返回最终状态，不更新交易状态：" + object.getString(EnumJsonProperty.RES_SUBORDERNO.toString()));
                        }
                    } catch (Exception e) {
                        log.info("更新预付款交易状态发生异常：" + e.getMessage());
                    }
                }
                // 批量更新交易状态
                if (!tPaymentUpdateList.isEmpty()) {
                    paymentService.updatePrePaymentStatusByOrderNo(tPaymentUpdateList);
                }
            } else {
                log.info("预付款交易状态查询返回报文错误：" + bodyVo.getBatchSerialNo());
            }

        } catch (Exception e) {
            log.info("预付款交易状态查询发生异常：" + e.getMessage());
        }
    }

    /**
     * 预付款退款交易状态推送
     *
     * @param tPaymentList 预付款退款集合
     */
    @Override
    public void prePaymentRefundStatusProcess(List<TPayment> tPaymentList) {
        try {
            //组装报文
            PrePaymentRefundStatusVo bodyVo = paymentService.fakePrePaymentStatusSendBody(tPaymentList, EnumCallBackOption.PRE_REFUND_STATUS.toString());
            log.info("预付款退款交易状态查询请求报文明文：" + JSON.toJSONString(bodyVo));

            //根据机构查询配置表获取URL,通用默认一个机构只有一个URL
            TOrgUrlManage orgUrlManage = orgUrlManageService.getOrgUrlByOrgCodeAndKey(bodyVo.getBankid(), EnumOrgType.BANK.toString(), EnumTaskCode.PRE_PAYMENT_REFUND_STATUS_PUSH.toString());
            String url = orgUrlManage.getInterfaceUrl();
            String publicKey = orgUrlManage.getPubCert();
            String requestBody = JSON.toJSONString(getCommonSendVo(bodyVo, bodyVo.getBankid(), bodyVo.getOrgCode(), EnumServiceCode.COM_FS0004.toString(), publicKey));
            Map<String, String> requestHeaders = okHttpUtil.getRequestHeaders(orgUrlManage.getAppKey(), url, bodyVo.getBankid());
            log.info("预付款退款交易状态查询请求报文密文：" + requestBody);

            //接口推送
            String responseBody = "";  //密文
            JSONObject jsonObject = new JSONObject();  //明文

            try {
                responseBody = okHttpUtil.doPostJson(url, requestBody, requestHeaders);
                jsonObject = JSONObject.parseObject(responseBody);
                log.info("预付款退款交易状态查询返回报文密文：" + responseBody);
                jsonObject.put(EnumJsonProperty.RES_DATA.toString(), JSONObject.parseObject(signHandler.decrypt(jsonObject.getString(EnumJsonProperty.RES_DATA.toString()))));
                log.info("预付款退款交易状态查询返回报文明文：" + JSON.toJSONString(jsonObject));
            } catch (Exception e) {
                log.info("预付款退款交易状态查询请求返回异常：" + e.getMessage());
            }

            //todo:根据返回处理剩余逻辑,调用成功，则更新paymentStatus
            //先按自己定义的返回来做通用处理
            CommonResDataVo commonResDataVo = getCommonResDataVo(jsonObject, EnumTaskCode.PRE_PAYMENT_REFUND_STATUS_PUSH.toString());
            JSONArray tranResult = jsonObject.getJSONObject(EnumJsonProperty.RES_DATA.toString()).getJSONArray(EnumJsonProperty.RES_TRANRESULT.toString());
            List<TPayment> tPaymentUpdateList = new ArrayList<>();
            if (BusiUtil.isEquals(EnumResultType.COM_TRAN_STATUS_SUCCESS.getStatusCode(), commonResDataVo.getCode())) {
                for (Object obj : tranResult) {
                    TPayment paymentUpdate = new TPayment();
                    try {
                        JSONObject object = (JSONObject) obj; // 确保对象是JSONObject类型
                        if (BusiUtil.isEquals(EnumResultType.COM_TRAN_STATUS_SUCCESS.getStatusCode(), object.getString(EnumJsonProperty.RES_STATUS.toString()))) {
                            // 交易成功，将0000回写到refund_status，将“交易成功”回写到refund_log，退款交易流水号回写到 refund_refids 同时将send2 更改成 N
                            log.info("预付款退款交易状态查询返回交易成功，修改状态为成功：" + object.getString(EnumJsonProperty.RES_SUBORDERNO.toString()));
                            paymentUpdate.setRefundBatchNo(bodyVo.getBatchSerialNo());
                            paymentUpdate.setSuborderno(object.getString(EnumJsonProperty.RES_SUBORDERNO.toString()));
                            paymentUpdate.setRefundStatus(EnumPaymentStatus.PAYMENT_SUCCESS.toString());
                            paymentUpdate.setRefundLog(EnumPaymentStatus.PAYMENT_SUCCESS_LOG.toString());
                            paymentUpdate.setRefundRefids(BusiUtil.nvl(object.getString(EnumJsonProperty.RES_BANKSEQNO.toString()), ""));  //银行交易流水号
                            if (BusiUtil.isNotNull(object.getString(EnumJsonProperty.RES_CORETIME.toString())) && object.getString(EnumJsonProperty.RES_CORETIME.toString()).length() == 14) {
                                paymentUpdate.setRefundWorkdate(DateUtil.dateToString(DateUtil.stringToDateTime(object.getString(EnumJsonProperty.RES_CORETIME.toString())), DateUtil.DATE_TIME_FORMAT));  //银行退款时间
                            }
                            paymentUpdate.setSend2("N");
                            tPaymentUpdateList.add(paymentUpdate);
                        } else if (BusiUtil.isEquals(EnumResultType.COM_TRAN_STATUS_FAIL.getStatusCode(), object.getString(EnumJsonProperty.RES_STATUS.toString()))) {
                            // 交易失败，将失败的状态码回写到refund_status，并将失败原因回写到refund_log
                            log.info("预付款退款交易状态查询返回交易失败，修改状态为失败：" + object.getString(EnumJsonProperty.RES_SUBORDERNO.toString()));
                            paymentUpdate.setRefundBatchNo(bodyVo.getBatchSerialNo());
                            paymentUpdate.setSuborderno(object.getString(EnumJsonProperty.RES_SUBORDERNO.toString()));
                            paymentUpdate.setRefundStatus(BusiUtil.nvl(object.getString(EnumJsonProperty.RES_CODE.toString()), EnumPaymentStatus.PAYMENT_FAIL.toString()));
                            paymentUpdate.setRefundLog(BusiUtil.nvl(object.getString(EnumJsonProperty.RES_MSG.toString()), EnumPaymentStatus.PAYMENT_FAIL_LOG.toString()));
                            tPaymentUpdateList.add(paymentUpdate);
                        } else {
                            // 报文未返回最终交易状态（成功、失败），不更新交易状态
                            log.info("预付款退款交易状态查询未返回最终状态，不更新交易状态：" + object.getString(EnumJsonProperty.RES_SUBORDERNO.toString()));
                        }
                    } catch (Exception e) {
                        log.info("更新预付款退款交易状态发生异常：" + e.getMessage());
                    }
                }
                // 批量更新交易状态
                if (!tPaymentUpdateList.isEmpty()) {
                    paymentService.updatePrePaymentRefundStatusByOrderNo(tPaymentUpdateList);
                }
            } else {
                log.info("预付款退款交易状态查询返回报文错误：" + bodyVo.getBatchSerialNo());
            }

        } catch (Exception e) {
            log.info("预付款退款交易状态查询发生异常：" + e.getMessage());
        }
    }

    /**
     * 跨境付汇状态查询推送处理
     *
     * @param settleTrades 跨境付汇集合
     */
    @Override
    public void settleTradeStatusProcess(List<SettleTrade> settleTrades) {
        for (SettleTrade settleTrade : settleTrades) {
            try {
                //组装报文
                SettleTradeStatusBodyVo bodyVo = new SettleTradeStatusBodyVo();
                BeanUtils.copyProperties(settleTrade, bodyVo);
                log.info("跨境付汇交易状态查询请求报文明文：" + JSON.toJSONString(bodyVo));
                //String updatePaymentStatus = "";

                //根据机构查询配置表获取URL,通用默认一个机构只有一个URL
                TOrgUrlManage orgUrlManage = orgUrlManageService.getOrgUrlByOrgCodeAndKey(settleTrade.getBankid().toString(), EnumOrgType.BANK.toString(), EnumTaskCode.SETTLE_TRADE_STATUS_PUSH.toString());
                String url = orgUrlManage.getInterfaceUrl();
                String publicKey = orgUrlManage.getPubCert();
                String requestBody = JSON.toJSONString(getCommonSendVo(bodyVo, settleTrade.getBankid().toString(), settleTrade.getOrgCode(), EnumServiceCode.COM_FS0006.toString(), publicKey));
                Map<String, String> requestHeaders = okHttpUtil.getRequestHeaders(orgUrlManage.getAppKey(), url, settleTrade.getBankid().toString());
                log.info("跨境付汇交易状态查询请求报文密文：" + requestBody);

                //接口推送
                String responseBody = "";  //密文
                JSONObject jsonObject = new JSONObject();  //明文
                try {
                    responseBody = okHttpUtil.doPostJson(url, requestBody, requestHeaders);
                    jsonObject = JSONObject.parseObject(responseBody);
                    log.info("跨境付汇交易状态查询返回报文密文：" + responseBody);
                    jsonObject.put(EnumJsonProperty.RES_DATA.toString(), JSONObject.parseObject(signHandler.decrypt(jsonObject.getString(EnumJsonProperty.RES_DATA.toString()))));
                    log.info("跨境付汇交易状态查询返回报文明文：" + JSON.toJSONString(jsonObject));
                } catch (Exception e) {
                    log.info("跨境付汇交易状态查询请求返回异常：" + e.getMessage());
                }

                //todo:根据返回处理剩余逻辑,调用成功，则更新paymentStatus
                //先按自己定义的返回来做通用处理
                CommonResDataVo commonResDataVo = getCommonResDataVo(jsonObject, EnumTaskCode.SETTLE_TRADE_STATUS_PUSH.toString());

                if (BusiUtil.isEquals(EnumResultType.COM_TRAN_STATUS_SUCCESS.getStatusCode(), commonResDataVo.getCode())) {
                    log.info("跨境付汇交易状态查询返回交易成功，修改状态为成功：" + settleTrade.getSettleId());
                    // 将review_status更改为2，deal_date为当前时间，deal_performer为银行直连机构号，review_date为当前时间
                    // 将review_performer为银行直连机构号，send2更改为N，serialnumber更改实际的跨境付款流水号
                    settleTrade.setReviewStatus(EnumPaymentStatus.SETTLE_REVIEW_SUCCESS.toString()); //银行审核付款成功
                    settleTrade.setDealDate(DateUtil.getCurrentLocalDateTime());  //当前时间
                    settleTrade.setDealPerformer(settleTrade.getOrgCode()); //银行直连机构号
                    settleTrade.setReviewDate(DateUtil.getCurrentLocalDateTime());  //当前时间
                    settleTrade.setReviewPerformer(settleTrade.getOrgCode());  //银行直连机构号
                    settleTrade.setSerialnumber(settleTrade.getSettleId());  //没有汇总订单的付款流水号，用settle_id代替
                    settleTrade.setSend2(EnumPaymentStatus.SETTLE_CANCEL_SEND.toString());

                    // 更新跨境订单交易表
                    log.info("更新跨境付汇订单状态为成功：" + settleTrade.getSettleId());
                    settleTradeService.updateSettleTradeStatusRefidsLog(settleTrade, EnumPaymentStatus.PAYMENT_SUCCESS.toString()); //更新交易成功状态

                    // 更新跨境订单明细表
                    log.info("更新跨境付订单汇明细状态为已跨境付汇：" + settleTrade.getSettleId());
                    settleTradeListService.updateSettleTradeListStatus(settleTrade.getSettleId(), "Y");

                } else if (BusiUtil.isEquals(EnumResultType.COM_TRAN_STATUS_FAIL.getStatusCode(), commonResDataVo.getCode())) {
                    log.info("跨境付汇交易状态查询返回交易失败，修改状态为成功：" + settleTrade.getSettleId());
                    // 将 review_status 更改为 3，reject_date 为当前时间，reject_performer 为银行直连机构号
                    // 将 remark 更改为银行返回的失败原因，cancel_send 更改为 N
                    settleTrade.setReviewStatus(EnumPaymentStatus.SETTLE_REVIEW_FAIL.toString()); //银行审核付款失败
                    settleTrade.setRejectDate(DateUtil.getCurrentLocalDateTime());  //当前时间
                    settleTrade.setRejectPerformer(settleTrade.getOrgCode()); //银行直连机构号
                    settleTrade.setRemark("银行驳回交易失败原因：" + BusiUtil.nvl(commonResDataVo.getMsg(), EnumPaymentStatus.PAYMENT_FAIL_LOG.toString()));  //失败原因
                    settleTrade.setCancelSend(EnumPaymentStatus.SETTLE_CANCEL_SEND.toString());

                    // 更新跨境订单交易表
                    log.info("更新跨境付汇订单状态为失败：" + settleTrade.getSettleId());
                    settleTradeService.updateSettleTradeStatusRefidsLog(settleTrade, EnumPaymentStatus.PAYMENT_FAIL.toString()); //更新交易失败状态

                    // 更新跨境订单明细表
                    log.info("更新跨境付订单汇明细状态为未跨境付汇：" + settleTrade.getSettleId());
                    settleTradeListService.updateSettleTradeListStatus(settleTrade.getSettleId(), "N");

                } else {
                    //跨境付订交易状态报文未返回最终状态
                    log.info("跨境付汇交易状态查询未返回最终状态：" + bodyVo.getSettleId());
                }
            } catch (Exception e) {
                log.info("跨境付汇交易状态查询交易发生异常：" + e.getMessage());
            }
        }
    }

    /**
     * 文件附件上传
     */
    @Override
    public void fileUploadJsonProcess(List<Enclosure> enclosureList) {
        for (Enclosure enclosure : enclosureList) {
            try {
                //组装报文
                FileUploadBase64Vo fileUploadBase64Vo = enclosureService.getFileUploadBase64ByMongdbid(enclosure);
                log.info("文件附件上传请求报文明文：" + JsonUtils.fieldValueReplace(JSON.toJSONString(fileUploadBase64Vo), "fileData", "......"));

                // 如果系统允许多个定时任务同时运行，或者多个线程运行，可能存在同一条待发送银行的记录在不同的定时任务中
                // 因此这里增加判断，如果该记录状态已经发送改变，可能是已发送银行，甚至都可能已经成功，那么该记录不再发送
                // 系统按批次更新交易状态，同一个批次同时更新为已发送银行，因此只需要判断批次其中一条记录的状态是否更改即可
                Enclosure dbEnclosure = enclosureService.getById(enclosure.getId());
                log.info("该批次交易数据库当前状态：" + dbEnclosure.getId() + "，bankSend：" + dbEnclosure.getBankSend() + "，fileId：" + dbEnclosure.getFileId());
                if (BusiUtil.isEquals(dbEnclosure.getBankSend(), "Y")) {
                    log.info("该批次交易数据库状态已经更改，不再发送至银行：" + dbEnclosure.getId());
                    return;
                }

                //根据机构查询配置表获取URL,通用默认一个机构只有一个URL
                TOrgUrlManage orgUrlManage = orgUrlManageService.getOrgUrlByOrgCodeAndKey(enclosure.getBankid(), EnumOrgType.BANK.toString(), EnumTaskCode.FILE_UPLOAD_PUSH.toString());
                String url = orgUrlManage.getInterfaceUrl();
                String publicKey = orgUrlManage.getPubCert();
                com.alibaba.fastjson2.JSON.config(com.alibaba.fastjson2.JSONWriter.Feature.LargeObject, true);  //序列化处理大型对象（文件）
                String requestBody = JSON.toJSONString(getCommonSendVo(fileUploadBase64Vo, enclosure.getBankid(), fileUploadBase64Vo.getOrgCode(), EnumServiceCode.COM_FS0010.toString(), publicKey));
                Map<String, String> requestHeaders = okHttpUtil.getRequestHeaders(orgUrlManage.getAppKey(), url, enclosure.getBankid());
                log.info("文件附件上传请求报文密文：" + JsonUtils.fieldValueReplace(requestBody, EnumJsonProperty.REQ_BODY.toString(), "......"));

                //接口推送
                String responseBody = "";  //密文
                JSONObject jsonObject = new JSONObject();  //明文
                try {
                    responseBody = okHttpUtil.doPostJson(url, requestBody, requestHeaders);
                    jsonObject = JSONObject.parseObject(responseBody);
                    log.info("文件附件上传返回报文密文：" + responseBody);
                    jsonObject.put(EnumJsonProperty.RES_DATA.toString(), JSONObject.parseObject(signHandler.decrypt(jsonObject.getString(EnumJsonProperty.RES_DATA.toString()))));
                    log.info("文件附件上传返回报文明文：" + JSON.toJSONString(jsonObject));
                } catch (Exception e) {
                    log.info("文件附件上传请求返回异常：" + e.getMessage());
                }

                JSONObject responseData = jsonObject.getJSONObject(EnumJsonProperty.RES_DATA.toString());
                String resCode = responseData.getString(EnumJsonProperty.RES_CODE.toString());
                String resMsg = responseData.getString(EnumJsonProperty.RES_MSG.toString());
                String fileIDs = responseData.getString("fileIDs");
                if (BusiUtil.isEquals(resCode, EnumResultType.COM_SUCCESS.getStatusCode()) && BusiUtil.isNotNull(fileIDs)) {
                    log.info("文件附件上传交易成功，更新文件流水号：" + fileIDs);
                    enclosure.setFileId(fileIDs);
                    enclosure.setBankSend("Y");
                    enclosureService.updateUploadBankFileId(enclosure);
                } else {
                    log.info("文件附件上传交易失败：" + resMsg);
                }
            } catch (Exception e) {
                log.info("文件附件上传交易发生异常：" + e.getMessage());
            }
        }
    }

    /**
     * 对账文件申请
     *
     * @param bankCheckFileVoList 对账集合
     */
    @Override
    public void bankCheckFileApplyProcess(List<BankCheckFileApplyVo> bankCheckFileVoList) {
        for (BankCheckFileApplyVo bankCheckFileVo : bankCheckFileVoList) {
            try {
                //组装报文
                log.info("对账文件申请请求报文明文：" + JSON.toJSONString(bankCheckFileVo));

                //根据机构查询配置表获取URL,通用默认一个机构只有一个URL
                TOrgUrlManage orgUrlManage = orgUrlManageService.getOrgUrlByOrgCodeAndKey(bankCheckFileVo.getBankid(), EnumOrgType.BANK.toString(), EnumTaskCode.BANK_CHECK_APPLY_PUSH.toString());
                String url = orgUrlManage.getInterfaceUrl();
                String publicKey = orgUrlManage.getPubCert();
                CommonSendVo<Object> commonSendVo = getCommonSendVo(bankCheckFileVo, bankCheckFileVo.getBankid(), "", EnumServiceCode.COM_FS0011.toString(), publicKey);
                CommonHeadSendVo commonHeadSendVo = commonSendVo.getCommonHeadSendVo();
                commonHeadSendVo.setOrgCode("ALL");  //ALL返回所有市场交易平台的对账记录，如果真实的交易平台编码，返回对应的对账记录
                commonSendVo.setCommonHeadSendVo(commonHeadSendVo);
                String requestBody = JSON.toJSONString(commonSendVo);
                Map<String, String> requestHeaders = okHttpUtil.getRequestHeaders(orgUrlManage.getAppKey(), url, bankCheckFileVo.getBankid());
                log.info("对账文件申请请求报文密文：" + requestBody);

                //接口推送
                String responseBody = "";  //密文
                JSONObject jsonObject = new JSONObject();  //明文
                try {
                    responseBody = okHttpUtil.doPostJson(url, requestBody, requestHeaders);
                    jsonObject = JSONObject.parseObject(responseBody);
                    log.info("对账文件申请返回报文密文：" + responseBody);
                    jsonObject.put(EnumJsonProperty.RES_DATA.toString(), JSONObject.parseObject(signHandler.decrypt(jsonObject.getString(EnumJsonProperty.RES_DATA.toString()))));
                    log.info("对账文件申请返回报文明文：" + JSON.toJSONString(jsonObject));
                } catch (Exception e) {
                    log.info("对账文件申请请求返回异常：" + e.getMessage());
                }

                //todo:根据返回处理剩余逻辑,调用成功，则更新paymentStatus
                //先按自己定义的返回来做通用处理
                String statusCode = jsonObject.getString(EnumJsonProperty.RES_STATUS_CODE.toString());  //银行返回报文处理状态，成功：000000
                JSONObject responseData = jsonObject.getJSONObject(EnumJsonProperty.RES_DATA.toString());
                String refNo = responseData.getString(EnumJsonProperty.RES_REFNO.toString());
                String code = responseData.getString(EnumJsonProperty.RES_CODE.toString());   //业务处理成功000000

                TCheckResult checkResult = new TCheckResult();
                checkResult.setApplyRefids(refNo);
                checkResult.setApplyStatus(EnumResultType.COM_TRAN_STATUS_FAIL.getStatusCode());
                checkResult.setDownStatus(EnumResultType.COM_TRAN_STATUS_FAIL.getStatusCode());  //未下载
                checkResult.setBankId(bankCheckFileVo.getBankid());
                checkResult.setCheckDate(bankCheckFileVo.getCheckDate());
                checkResult.setCheckTime(DateUtil.getCurrentLocalDateTime());
                checkResult.setBatchNo(BusiUtil.getSerialNumber(bankCheckFileVo.getBankid(), "", 5));

                // 因存在对账申请失败的可能，定时任务多次申请，直到申请成功，因此根据返回报文判断对账申请是否成功，更新对账文件申请状态apply_status
                if (BusiUtil.isNotNullAll(jsonObject, statusCode, responseData, refNo, code)
                        && BusiUtil.isEquals(EnumResultType.COM_SUCCESS.getStatusCode(), statusCode)
                        && BusiUtil.isEquals(code, EnumResultType.COM_FILE_SUCCESS.getStatusCode())) {
                    checkResult.setApplyStatus(EnumResultType.COM_TRAN_STATUS_SUCCESS.getStatusCode());
                }

                // 查询对账申请是否已经存在，如果存在更新，否则插入一条记录，保证一个银行，每天最多一条记录
                log.info("查询对账申请是否已经存在：" + bankCheckFileVo.getBankid() + "-" + DateUtil.dateToString(bankCheckFileVo.getCheckDate(), DateUtil.DATE_FORMAT));
                TCheckResult queryCheckResult = checkResultService.getOne(
                        new QueryWrapper<TCheckResult>().eq("bank_id", bankCheckFileVo.getBankid()).eq("check_date", bankCheckFileVo.getCheckDate()));

                // 更新或保存对账申请记录
                if (BusiUtil.isNull(queryCheckResult)) {
                    log.info("不存在，新增对账申请记录：银行编号" + bankCheckFileVo.getBankid() + "，对账日期" + DateUtil.dateToString(bankCheckFileVo.getCheckDate(), DateUtil.DATE_FORMAT));
                    checkResultService.saveOrUpdate(checkResult);
                } else {
                    log.info("已存在，更新对账申请状态：银行编号" + bankCheckFileVo.getBankid() + "，对账日期" + DateUtil.dateToString(bankCheckFileVo.getCheckDate(), DateUtil.DATE_FORMAT));
                    checkResultService.update(checkResult, new UpdateWrapper<TCheckResult>().
                            eq("bank_id", bankCheckFileVo.getBankid()).
                            eq("check_date", bankCheckFileVo.getCheckDate()));
                }

            } catch (Exception e) {
                log.info("对账文件申请交易发生异常：" + e.getMessage());
            }
        }
    }

    /**
     * 对账文件下载
     *
     * @param bankCheckFileDownVoList 对账集合
     */
    @Override
    public void bankCheckFileDownLoadProcess(List<BankCheckFileDownVo> bankCheckFileDownVoList) {
        for (BankCheckFileDownVo bankCheckFileDownVo : bankCheckFileDownVoList) {
            try {
                //组装报文
                log.info("对账文件下载请求报文：" + JSON.toJSONString(bankCheckFileDownVo));
                TOrgUrlManage orgUrlManage = orgUrlManageService.getOrgUrlByOrgCodeAndKey(bankCheckFileDownVo.getBankId(), EnumOrgType.BANK.toString(), EnumTaskCode.BANK_CHECK_DOWN_PUSH.toString());
                String url = orgUrlManage.getInterfaceUrl();
                String publicKey = orgUrlManage.getPubCert();
                CommonSendVo<Object> commonSendVo = getCommonSendVo(bankCheckFileDownVo, bankCheckFileDownVo.getBankId(), "", EnumServiceCode.COM_FS0012.toString(), publicKey);
                CommonHeadSendVo commonHeadSendVo = commonSendVo.getCommonHeadSendVo();
                commonHeadSendVo.setOrgCode("ALL");
                commonSendVo.setCommonHeadSendVo(commonHeadSendVo);
                String requestBody = JSON.toJSONString(commonSendVo);
                Map<String, String> requestHeaders = okHttpUtil.getRequestHeaders(orgUrlManage.getAppKey(), url, bankCheckFileDownVo.getBankId());

                //接口推送
                String responseBody = "";  //密文
                JSONObject jsonObject = new JSONObject();  //明文
                try {
                    responseBody = okHttpUtil.doPostJson(url, requestBody, requestHeaders);
                    jsonObject = JSONObject.parseObject(responseBody);
                    log.info("对账文件下载返回报文密文：" + responseBody);
                    jsonObject.put(EnumJsonProperty.RES_DATA.toString(), JSONObject.parseObject(signHandler.decrypt(jsonObject.getString(EnumJsonProperty.RES_DATA.toString()))));
                    log.info("对账文件下载返回报文明文：" + JSON.toJSONString(jsonObject));
                } catch (Exception e) {
                    log.info("对账文件下载请求返回异常：" + e.getMessage());
                }

                //todo:根据返回处理剩余逻辑,调用成功，则更新paymentStatus
                //先按自己定义的返回来做通用处理
                String statusCode = jsonObject.getString(EnumJsonProperty.RES_STATUS_CODE.toString());  //银行返回报文处理状态，成功：000000
                JSONObject responseData = jsonObject.getJSONObject(EnumJsonProperty.RES_DATA.toString());
                String dealStatus = responseData.getString(EnumJsonProperty.RES_DEALSTATUS.toString());
                String code = responseData.getString(EnumJsonProperty.RES_CODE.toString());   //业务处理成功000000
                String data = responseData.getString(EnumJsonProperty.RES_BASE64DATE.toString());   //对账文件Base64
                String checkDate = DateUtil.dateToString(bankCheckFileDownVo.getCheckDate(), DateUtil.DATE_FORMAT);

                if (BusiUtil.isNotNullAll(jsonObject, statusCode, responseData, dealStatus, code, data)
                        && BusiUtil.isEquals(EnumResultType.COM_SUCCESS.getStatusCode(), statusCode)
                        && BusiUtil.isEquals(code, EnumResultType.COM_FILE_SUCCESS.getStatusCode())) {
                    if (BusiUtil.isEquals(dealStatus, EnumResultType.COM_TRAN_STATUS_SUCCESS.getStatusCode())) {
                        // 对账文件下载返回成功
                        log.info("对账文件下载返回成功：银行" + bankCheckFileDownVo.getBankId() + "，对账日期" + bankCheckFileDownVo.getCheckDate());
                        String filePath = applicationPropertiesVo.getAppCheckFilePath()  + checkDate + "/" ;
                        String filePathName = filePath + bankCheckFileDownVo.getBankId() + "_" + checkDate + ".zip";
                        if (!(new File(filePath).isDirectory())) {
                            boolean flag = new File(filePath).mkdir();
                        }
                        log.info("保存对账文件名路径：" + filePathName);
                        FileToBase64.getBase64ToFile(filePathName, data);
                        log.info("解压对账文件名路径：" + filePath + bankCheckFileDownVo.getBankId() + "_" + checkDate + ".txt");
                        byte[] unzipByte = BusiUtil.unzip(Files.readAllBytes(Paths.get(filePathName)));
                        FileToBase64.byteToFile(filePath + bankCheckFileDownVo.getBankId() + "_" + checkDate + ".txt", unzipByte);
                        String content = FileToBase64.readTextFileToString(filePath + bankCheckFileDownVo.getBankId() + "_" + checkDate + ".txt", "UTF-8");
                        String[] fileArray = content.split(System.getProperties().getProperty("line.separator"));
                        List<TCheckDetail> paymentCheckDetailList = new ArrayList<>();
                        List<TCheckDetail> refundCheckDetailList = new ArrayList<>();
                        List<TCheckDetail> settleCheckDetailList = new ArrayList<>();

                        // 对账文件格式：机构编号|交易日期|订单编号|交易类型（11-预扣款12-预扣款退款14-跨境付汇）|交易状态|交易流水号|交易时间|交易失败原因
                        // 判断对账文件格式是否正确
                        for (String fileStr : fileArray) {
                            String[] lineCellArray = fileStr.split("\\|");
                            String fileDate = lineCellArray[1];  //交易日期
                            String checkType = lineCellArray[3];  //交易类型
                            if (lineCellArray.length != 8) {
                                log.info("银行返回对账文件格式错误：" + fileStr);
                                throw new Exception("银行返回对账文件格式错误");
                            } else if (!BusiUtil.isEquals(checkType, "11") && !BusiUtil.isEquals(checkType, "12") && !BusiUtil.isEquals(checkType, "14")) {
                                log.info("银行返回对账交易类型错误：" + fileStr);
                                throw new Exception("银行返回对账交易类型错误");
                            } else if (DateUtil.compare_date(checkDate, DateUtil.DateToString(fileDate)) != 0) {
                                log.info("银行返回对账文件日期错误：" + fileStr);
                                throw new Exception("银行返回对账文件日期错误");
                            }
                        }
                        for (String fileStr : fileArray) {
                            TCheckDetail checkDetail = new TCheckDetail();
                            String[] lineCellArray = fileStr.split("\\|");
                            String orgCode = lineCellArray[0];  //机构编号
                            String fileDate = lineCellArray[1];  //交易日期
                            String suborderno = lineCellArray[2];  //订单编号
                            String checkType = lineCellArray[3];  //交易类型
                            String checkStatus = lineCellArray[4];  //交易状态
                            String checkRefids = lineCellArray[5];  //交易流水号
                            String checkTime = lineCellArray[6];  //交易时间
                            String checkLog = lineCellArray[7];  //交易失败原因

                            checkDetail.setCheckDate(DateUtil.stringToDate(fileDate, DateUtil.DATE_SIMP_FORMAT));
                            checkDetail.setSuborderno(suborderno);
                            if (BusiUtil.isEquals(checkStatus, EnumResultType.COM_TRAN_STATUS_SUCCESS.getStatusCode())) {
                                // 兼容处理，建行交易成功状态00
                                checkDetail.setBankStatus("00");
                            } else if (BusiUtil.isEquals(checkStatus, EnumResultType.COM_TRAN_STATUS_FAIL.getStatusCode())) {
                                // 兼容处理，建行交易失败状态01
                                checkDetail.setBankStatus("01");
                            }
                            checkDetail.setBankRefids(checkRefids);
                            checkDetail.setBankLog(checkLog);
                            checkDetail.setTranDate(DateUtil.stringToDate(checkTime, DateUtil.DATE_TIME_HM_FORMAT));
                            checkDetail.setBatchNo(bankCheckFileDownVo.getBatchNo());
                            checkDetail.setEffectiveStatus("Y");
                            checkDetail.setTotalCount(Integer.toString(fileArray.length));
                            checkDetail.setCheckTime(DateUtil.getCurrentLocalDateTime());
                            checkDetail.setBankId(bankCheckFileDownVo.getBankId());

                            if (BusiUtil.isEquals(checkType, "11")) {
                                //预付款日终对账
                                checkDetail.setCheckType(EnumCheckType.PRE_PAYMENT_CHECK.toString());
                                paymentCheckDetailList.add(checkDetail);
                            } else if (BusiUtil.isEquals(checkType, "12")) {
                                //预付款退款日终对账
                                checkDetail.setCheckType(EnumCheckType.REFUND_CHECK.toString());
                                refundCheckDetailList.add(checkDetail);
                            } else if (BusiUtil.isEquals(checkType, "14")) {
                                //跨境付汇日终对账
                                checkDetail.setCheckType(EnumCheckType.SETTLE_TRADE_CHECK.toString());
                                settleCheckDetailList.add(checkDetail);
                            }
                        }
                        //可能多次对账，因此先更新记录为失效状态，再保存最新记录
                        if (!paymentCheckDetailList.isEmpty()) {
                            // 判断文件内容日期是否正确：文件对账日期是否等于对账申请日期
                            //Map<Date, List<TCheckDetail>> paymentMap = paymentCheckDetailList.stream().collect(Collectors.groupingBy(TCheckDetail::getCheckDate));
                            log.info("更新银行预付款日终对账结果为失效状态：" + checkDate + "，批次号" + bankCheckFileDownVo.getBatchNo());
                            checkDetailService.updateCheckDetailByDate("N", bankCheckFileDownVo.getBankId(), DateUtil.stringToDate(checkDate), EnumCheckType.PRE_PAYMENT_CHECK.toString());
                            //批量保存
                            log.info("保存银行预付款日终对账结果：" + checkDate + "，批次号" + bankCheckFileDownVo.getBatchNo());
                            checkDetailService.saveBatch(paymentCheckDetailList);
                        }
                        if (!refundCheckDetailList.isEmpty()) {
                            // 判断文件内容日期是否正确：文件对账日期是否等于对账申请日期
                            //Map<Date, List<TCheckDetail>> refundMap = refundCheckDetailList.stream().collect(Collectors.groupingBy(TCheckDetail::getCheckDate));
                            log.info("更新银行预付款退款日终对账结果为失效状态：" + checkDate + "，批次号" + bankCheckFileDownVo.getBatchNo());
                            checkDetailService.updateCheckDetailByDate("N", bankCheckFileDownVo.getBankId(), DateUtil.stringToDate(checkDate), EnumCheckType.REFUND_CHECK.toString());
                            //批量保存
                            log.info("保存银行预付款退款日终对账结果：" + checkDate + "，批次号" + bankCheckFileDownVo.getBatchNo());
                            checkDetailService.saveBatch(refundCheckDetailList);
                        }
                        if (!settleCheckDetailList.isEmpty()) {
                            // 判断文件内容日期是否正确：文件对账日期是否等于对账申请日期
                            //Map<Date, List<TCheckDetail>> settleMap = settleCheckDetailList.stream().collect(Collectors.groupingBy(TCheckDetail::getCheckDate));
                            log.info("更新银行跨境付汇日终对账结果为失效状态：" + checkDate + "，批次号" + bankCheckFileDownVo.getBatchNo());
                            checkDetailService.updateCheckDetailByDate("N", bankCheckFileDownVo.getBankId(), DateUtil.stringToDate(checkDate), EnumCheckType.SETTLE_TRADE_CHECK.toString());
                            //批量保存
                            log.info("保存银行跨境付汇日终对账结果：" + checkDate + "，批次号" + bankCheckFileDownVo.getBatchNo());
                            checkDetailService.saveBatch(settleCheckDetailList);
                        }

                        //查询预付款对账不符合的数据
                        TCheckResult checkResult = new TCheckResult();
                        checkResult.setDownStatus(EnumResultType.COM_TRAN_STATUS_SUCCESS.getStatusCode());
                        checkResult.setCheckTime(DateUtil.getCurrentLocalDateTime());
                        checkResult.setBatchNo(bankCheckFileDownVo.getBatchNo());
                        checkResult.setCheckResult(EnumResultType.COM_TRAN_STATUS_SUCCESS.getStatusCode());

                        log.info("查询预付款对账不符合的数据：" + checkDate);
                        List<TCheckDetail> paymentCheckResultList = checkDetailService.getPrePaymentResultByCheckDate(bankCheckFileDownVo.getBankId(), bankCheckFileDownVo.getCheckDate(), EnumCheckType.PRE_PAYMENT_CHECK.toString());

                        log.info("查询预付款退款对账不符合的数据：" + checkDate);
                        List<TCheckDetail> refundCheckResultList = checkDetailService.getPrePaymentRefundResultByCheckDate(bankCheckFileDownVo.getBankId(), bankCheckFileDownVo.getCheckDate(), EnumCheckType.REFUND_CHECK.toString());

                        log.info("查询跨境付汇对账不符合的数据：" + checkDate);
                        List<TCheckDetail> settleCheckResultList =checkDetailService.getSettleResultByCheckDate(bankCheckFileDownVo.getBankId(), bankCheckFileDownVo.getCheckDate(), EnumCheckType.SETTLE_TRADE_CHECK.toString());

                        // 判断对账结果是否符合
                        if (paymentCheckResultList.isEmpty() && refundCheckResultList.isEmpty() && settleCheckResultList.isEmpty()){
                            checkResult.setErrorNum(0);
                            checkResult.setCheckResult(EnumResultType.COM_TRAN_STATUS_SUCCESS.getStatusCode());  //对账结果相符
                        } else {
                            checkResult.setErrorNum(paymentCheckResultList.size() + refundCheckResultList.size() + settleCheckResultList.size());
                            checkResult.setCheckResult(EnumResultType.COM_TRAN_STATUS_FAIL.getStatusCode());  //对账结果不符
                        }

                        log.info("互联互通与银行预付款对账：银行编号：" + bankCheckFileDownVo.getBankId()  + "，对账日期" + checkDate + "，批次号" + bankCheckFileDownVo.getBatchNo());
                        bankCheckResultService.checkPayment(paymentCheckResultList, bankCheckFileDownVo.getBankId(), bankCheckFileDownVo.getBatchNo());

                        log.info("互联互通与银行预付款退款对账：银行编号：" + bankCheckFileDownVo.getBankId()  + "，对账日期" + checkDate + "，批次号" + bankCheckFileDownVo.getBatchNo());
                        bankCheckResultService.checkRefund(refundCheckResultList, bankCheckFileDownVo.getBankId(), bankCheckFileDownVo.getBatchNo());

                        log.info("互联互通与银行跨境付汇对账：银行编号：" + bankCheckFileDownVo.getBankId()  + "，对账日期" + checkDate + "，批次号" + bankCheckFileDownVo.getBatchNo());
                        bankCheckResultService.checkSettle(settleCheckResultList, bankCheckFileDownVo.getBankId(), bankCheckFileDownVo.getBatchNo());

                        log.info("更新互联互通与银行对账结果：银行编号：" + bankCheckFileDownVo.getBankId()  + "，对账日期" + checkDate + "，批次号" + bankCheckFileDownVo.getBatchNo());
                        checkResultService.update(checkResult, new UpdateWrapper<TCheckResult>().
                                eq("bank_id", bankCheckFileDownVo.getBankId()).
                                eq("check_date", bankCheckFileDownVo.getCheckDate()).
                                eq("batch_no", bankCheckFileDownVo.getBatchNo()));
                    } else if (BusiUtil.isEquals(dealStatus, EnumResultType.COM_TRAN_STATUS_PROCESS.getStatusCode())) {
                        // 对账文件下载返回处理中
                        log.info("对账文件下载返回处理中：银行编号" + bankCheckFileDownVo.getBankId() + "，对账日期" + checkDate + "，批次号" + bankCheckFileDownVo.getBatchNo());
                    } else {
                        // 对账文件下载返回处理中
                        log.info("对账文件下载返回状态失败：银行编号" + bankCheckFileDownVo.getBankId() + "，对账日期" + checkDate + "，批次号" + bankCheckFileDownVo.getBatchNo());
                    }
                } else {
                    log.info("对账文件下载返回失败：银行编号" + bankCheckFileDownVo.getBankId() + "，对账日期" + checkDate + "，批次号" + bankCheckFileDownVo.getBatchNo());
                }

            } catch (Exception e) {
                log.info("对账文件下载交易发生异常：" + e.getMessage());
            }
        }
    }

    /**
     * 建行对账推送-JSON格式
     *
     * @param ccbBankCheckJsonVoList 对账集合
     */
    @Override
    public void ccbBankCheckJsonProcess(List<CCBBankCheckJsonVo> ccbBankCheckJsonVoList) {

    }

    /**
     * 获取处理器类型
     */
    @Override
    public String getProcessorForBranch() {

        return EnumBranch.COMMON.toString();
    }

    /**
     * 组装银行发送报文
     *
     * @param sendVo 发送报文
     */
    private CommonSendVo<Object> getCommonSendVo(CommonDataSendVo sendVo, String bankId, String orgCode, String serviceCode, String publicKey) {
        CommonHeadSendVo commonHeadSendVo = new CommonHeadSendVo();
        if (BusiUtil.isNotNull(orgCode)) {
            try {
                TOrgConfig orgConfig = orgConfigService.getOrgConfigByOrgCode(orgCode);
                commonHeadSendVo.setOrgCode(BusiUtil.nvl(orgConfig.getPlatidS(), ""));
            } catch (Exception e) {
                commonHeadSendVo.setOrgCode(BusiUtil.nvl(orgCode, ""));
                log.info(serviceCode + "查询平台编码异常：" + e.getMessage());
            }
        }
        commonHeadSendVo.setBankId(bankId);
        commonHeadSendVo.setChannelSeqNo(bankId + commonHeadSendVo.getChannelSeqNo());
        commonHeadSendVo.setServiceCode(serviceCode);
        CommonSendVo<Object> commonSendVo = new CommonSendVo<>();
        commonSendVo.setCommonHeadSendVo(commonHeadSendVo);  //head部分
        JSONObject jsonObject = new JSONObject();
        jsonObject.put(EnumJsonProperty.REQ_SYS_HEAD.toString(), commonHeadSendVo);
        jsonObject.put(EnumJsonProperty.REQ_BODY.toString(), sendVo);
        if (BusiUtil.isNotEquals(EnumServiceCode.COM_FS0010.toString(), serviceCode)) {
            log.info("请求报文加密前明文：" + JSON.toJSONString(jsonObject));
        }
        signHandler.encrypt(JSON.toJSONString(sendVo), publicKey);
        commonSendVo.setBody(signHandler.encrypt(JSON.toJSONString(sendVo), publicKey));  //body部分
        return commonSendVo;
    }

    /**
     * 判断交易状态，根据返回结果更新交易状态，返回空不进行任何处理，由系统重新推送至银行，银行判断且控制重复交易
     *
     * @param jsonObject 返回报文
     * @param taskCode   定时任务
     */
    private CommonResDataVo getCommonResDataVo(JSONObject jsonObject, String taskCode) {
        String statusCode = "";  //银行返回报文处理状态，成功：000000
        CommonResDataVo commonResDataVo = new CommonResDataVo();
        JSONObject responseData = new JSONObject();

        try {
            statusCode = jsonObject.getString(EnumJsonProperty.RES_STATUS_CODE.toString());
        } catch (Exception e) {
            log.info("解析返回报文head返回码异常：" + e.getMessage());
        }
        try {
            responseData = jsonObject.getJSONObject(EnumJsonProperty.RES_DATA.toString());
        } catch (Exception e) {
            log.info("解析返回报文body返回码异常：" + e.getMessage());
        }

        // 判断接口返回报文是否返回成功标志：000000
        if (BusiUtil.isNotEquals(EnumResultType.COM_SUCCESS.getStatusCode(), statusCode) || BusiUtil.isNull(responseData)) {
            return commonResDataVo;
        }

        if (BusiUtil.isEquals(taskCode, EnumTaskCode.PRE_PAYMENT_PUSH.toString()) ||
                BusiUtil.isEquals(taskCode, EnumTaskCode.PRE_PAYMENT_REFUND_PUSH.toString())) {
            // 预付款推送、预付款退款推送
            commonResDataVo = JSON.parseObject(jsonObject.getJSONObject(EnumJsonProperty.RES_DATA.toString()).toJSONString(), CommonResDataVo.class);
            if (BusiUtil.isEquals(EnumResultType.COM_SUCCESS.getStatusCode(), commonResDataVo.getCode())) {
                commonResDataVo.setCode(EnumResultType.COM_TRAN_STATUS_SUCCESS.getStatusCode());
            } else if (BusiUtil.isNotNull(commonResDataVo.getCode()) && BusiUtil.isNotEquals(EnumResultType.COM_SUCCESS.getStatusCode(), commonResDataVo.getCode())) {
                commonResDataVo.setCode(EnumResultType.COM_TRAN_STATUS_FAIL.getStatusCode());
                commonResDataVo.setMsg(BusiUtil.nvl(commonResDataVo.getMsg(), EnumPaymentStatus.PAYMENT_FAIL_LOG.toString()));
            }
        } else if (BusiUtil.isEquals(taskCode, EnumTaskCode.SETTLE_TRADE_PUSH.toString())) {
            // 跨境付汇推送
            commonResDataVo = JSON.parseObject(jsonObject.getJSONObject(EnumJsonProperty.RES_DATA.toString()).toJSONString(), CommonResDataVo.class);
            if (BusiUtil.isEquals(commonResDataVo.getStatus(), EnumResultType.COM_TRAN_STATUS_FAIL.toString())) {
                commonResDataVo.setMsg(BusiUtil.nvl(commonResDataVo.getMsg(), EnumPaymentStatus.PAYMENT_FAIL_LOG.toString()));
            }
            commonResDataVo.setMsg(BusiUtil.nvl(commonResDataVo.getMsg(), EnumPaymentStatus.PAYMENT_FAIL_LOG.toString()));
        } else if (BusiUtil.isEquals(taskCode, EnumTaskCode.PRE_PAYMENT_STATUS_PUSH.toString()) ||
                BusiUtil.isEquals(taskCode, EnumTaskCode.PRE_PAYMENT_REFUND_STATUS_PUSH.toString())) {
            // 预付款付款交易状态、预付款退款交易状态
            JSONArray tranResult = jsonObject.getJSONObject(EnumJsonProperty.RES_DATA.toString()).getJSONArray(EnumJsonProperty.RES_TRANRESULT.toString());
            if (BusiUtil.isNotNull(tranResult)) {
                commonResDataVo.setCode(EnumResultType.COM_TRAN_STATUS_SUCCESS.getStatusCode());
            }
        } else if (BusiUtil.isEquals(taskCode, EnumTaskCode.SETTLE_TRADE_STATUS_PUSH.toString())) {
            // 跨境付汇交易状态
            String rsCode = BusiUtil.nvl(responseData.getString(EnumJsonProperty.RES_RSCODE.toString()), "");
            String rsDesc = BusiUtil.nvl(responseData.getString(EnumJsonProperty.RES_RSDESC.toString()), "");
            String status = BusiUtil.nvl(responseData.getString(EnumJsonProperty.RES_STATUS.toString()), "");
            if (BusiUtil.isEquals(EnumResultType.COM_SUCCESS.getStatusCode(), rsCode) && BusiUtil.isEquals(EnumResultType.COM_TRAN_FINISH.getStatusCode(), status)) {
                commonResDataVo.setCode(EnumResultType.COM_TRAN_STATUS_SUCCESS.getStatusCode());
            } else if (BusiUtil.isEquals(EnumResultType.COM_SUCCESS.getStatusCode(), rsCode) && BusiUtil.isEquals(EnumResultType.COM_TRAN_CANCEL.getStatusCode(), status)) {
                commonResDataVo.setCode(EnumResultType.COM_TRAN_STATUS_FAIL.getStatusCode());
                commonResDataVo.setMsg(BusiUtil.nvl(rsDesc, EnumPaymentStatus.PAYMENT_FAIL_LOG.toString()));
            }
        }
        return commonResDataVo;
    }

}
